use std::{collections::HashMap, sync::{Arc, Mutex}};

use once_cell::sync::Lazy;


static ALLOCATED: Lazy<Arc<Mutex<HashMap<i64, Vec<u8>>>>> = Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));
static NEXT_ADDRESS: Lazy<Arc<Mutex<i64>>> = Lazy::new(|| Arc::new(Mutex::new(64))); // not zero!

pub fn allocate(size: i64) -> i64 {
    let mem = (0..size).map(|_| 0u8).collect();
    let address = *NEXT_ADDRESS.lock().unwrap();
    ALLOCATED.lock().unwrap().insert(address, mem);
    *NEXT_ADDRESS.lock().unwrap() += size;
    return address;
}

pub fn reallocate(address: i64, size: i64) -> i64 {
    if size == 0 {
        return 0;
    } else if address == 0 {
        return allocate(size);
    } else {
        let mem = memory_at(address);
        if mem.len() >= size as usize {
            return address;
        } else {
            ALLOCATED.lock().unwrap().remove(&address);
            let new_address = allocate(size);
            let new_mwm = memory_at(new_address);
            // newMem := memoryAt(newAddress)
			// copy(newMem, mem)
            memory_copy(new_address, &mem); // copy
            return new_address
        }
    }
    0
}

pub fn free(address: i64) {
    if ALLOCATED.lock().unwrap().remove(&address).is_none() {
        panic!("memory was not allocated!");
    }
}

pub fn memory_at(address: i64) -> Vec<u8> {
    for (start_address, men) in ALLOCATED.lock().unwrap().iter() {
        let end_address = start_address + men.len() as i64;
        if address >= *start_address && address < end_address  {
            let offset = (address - *start_address) as usize;
            return men[offset..].to_vec()
        }
    }
    panic!("invalid address!");
    vec![]
}

// 拷贝,将mem中的数据拷贝到address处
pub fn memory_copy(address: i64, mem: &[u8]) {
    for (start_address, new_men) in ALLOCATED.lock().unwrap().iter_mut() {
        let end_address = start_address + new_men.len() as i64;
        if address >= *start_address && address < end_address  {
            let offset = (address - *start_address) as usize;
            for i in 0..mem.len() {
                new_men[offset + i] = mem[i];
            }
            return;
        }
    }
    panic!("invalid address!");
}

